var JpegMeta = {};
this.JpegMeta = JpegMeta;
JpegMeta.parseNum = function parseNum(endian, data, offset, size) {
	var i;
	var ret;
	var big_endian = (endian === ">");
	if (offset === undefined)
		offset = 0;
	if (size === undefined)
		size = data.length - offset;
	for (big_endian ? i = offset : i = offset + size - 1; big_endian ? i < offset
			+ size
			: i >= offset; big_endian ? i++ : i--) {
		ret <<= 8;
		ret += data.charCodeAt(i);
	}
	return ret;
};
JpegMeta.parseSnum = function parseSnum(endian, data, offset, size) {
	var i;
	var ret;
	var neg;
	var big_endian = (endian === ">");
	if (offset === undefined)
		offset = 0;
	if (size === undefined)
		size = data.length - offset;
	for (big_endian ? i = offset : i = offset + size - 1; big_endian ? i < offset
			+ size
			: i >= offset; big_endian ? i++ : i--) {
		if (neg === undefined) {
			neg = (data.charCodeAt(i) & 0x80) === 0x80;
		}
		ret <<= 8;
		ret += neg ? ~data.charCodeAt(i) & 0xff : data.charCodeAt(i);
	}
	if (neg) {
		ret += 1;
		ret *= -1;
	}
	return ret;
};
JpegMeta.Rational = function Rational(num, den) {
	this.num = num;
	this.den = den || 1;
	return this;
};
JpegMeta.Rational.prototype.toString = function toString() {
	if (this.num === 0) {
		return "" + this.num;
	}
	if (this.den === 1) {
		return "" + this.num;
	}
	if (this.num === 1) {
		return this.num + " / " + this.den;
	}
	return this.num / this.den;
};
JpegMeta.Rational.prototype.asFloat = function asFloat() {
	return this.num / this.den;
};
JpegMeta.MetaGroup = function MetaGroup(fieldName, description) {
	this.fieldName = fieldName;
	this.description = description;
	this.metaProps = {};
	return this;
};
JpegMeta.MetaGroup.prototype._addProperty = function _addProperty(fieldName,
		description, value) {
	var property = new JpegMeta.MetaProp(fieldName, description, value);
	this[property.fieldName] = property;
	this.metaProps[property.fieldName] = property;
};
JpegMeta.MetaGroup.prototype.toString = function toString() {
	return "[MetaGroup " + this.description + "]";
};
JpegMeta.MetaProp = function MetaProp(fieldName, description, value) {
	this.fieldName = fieldName;
	this.description = description;
	this.value = value;
	return this;
};
JpegMeta.MetaProp.prototype.toString = function toString() {
	return "" + this.value;
};
JpegMeta.JpegFile = function JpegFile(binary_data, filename) {
	var break_segment = this._SOS;
	this.metaGroups = {};
	this._binary_data = binary_data;
	this.filename = filename;
	var pos = 0;
	var pos_start_of_segment = 0;
	var delim;
	var mark;
	var _mark;
	var segsize;
	var headersize;
	var mark_code;
	var mark_fn;
	if (this._binary_data.slice(0, 2) !== this._SOI_MARKER) {
		throw new Error("Doesn't look like a JPEG file. First two bytes are "
				+ this._binary_data.charCodeAt(0) + ","
				+ this._binary_data.charCodeAt(1) + ".");
	}
	pos += 2;
	while (pos < this._binary_data.length) {
		delim = this._binary_data.charCodeAt(pos++);
		mark = this._binary_data.charCodeAt(pos++);
		// console.log(mark.toString(16))
		pos_start_of_segment = pos;
		if (delim != this._DELIM) {
			break;
		}
		if (mark === break_segment) {
			break;
		}
		headersize = JpegMeta.parseNum(">", this._binary_data, pos, 2);
		// console.log('headsize=' + headersize)
		pos += headersize;
		while (pos < this._binary_data.length) {
			delim = this._binary_data.charCodeAt(pos++);
			if (delim == this._DELIM) {
				_mark = this._binary_data.charCodeAt(pos++);
				if (_mark != 0x0) {
					pos -= 2;
					break;
				}
			}
		}
		segsize = pos - pos_start_of_segment;
		if (this._markers[mark]) {
			mark_code = this._markers[mark][0];
			mark_fn = this._markers[mark][1];
		} else {
			mark_code = "UNKN";
			mark_fn = undefined;
		}
		if (mark_fn) {
			this[mark_fn](mark, pos_start_of_segment + 2);
		}
	}
	if (this.general === undefined) {
		throw Error("Invalid JPEG file.");
	}
	return this;
};
this.JpegMeta.JpegFile.prototype.toString = function() {
	return "[JpegFile " + this.filename + " " + this.general.type + " "
			+ this.general.pixelWidth + "x" + this.general.pixelHeight
			+ " Depth: " + this.general.depth + "]";
};
this.JpegMeta.JpegFile.prototype._SOI_MARKER = '\xff\xd8';
this.JpegMeta.JpegFile.prototype._DELIM = 0xff;
this.JpegMeta.JpegFile.prototype._EOI = 0xd9;
this.JpegMeta.JpegFile.prototype._SOS = 0xda;
this.JpegMeta.JpegFile.prototype._sofHandler = function _sofHandler(mark, pos) {
	if (this.general !== undefined) {
		throw Error("Unexpected multiple-frame image");
	}
	this._addMetaGroup("general", "General");
	this.general._addProperty("depth", "Depth", JpegMeta.parseNum(">",
			this._binary_data, pos, 1));
	this.general._addProperty("pixelHeight", "Pixel Height", JpegMeta.parseNum(
			">", this._binary_data, pos + 1, 2));
	this.general._addProperty("pixelWidth", "Pixel Width", JpegMeta.parseNum(
			">", this._binary_data, pos + 3, 2));
	this.general._addProperty("type", "Type", this._markers[mark][2]);
};
this.JpegMeta.JpegFile.prototype._JFIF_IDENT = "JFIF\x00";
this.JpegMeta.JpegFile.prototype._JFXX_IDENT = "JFXX\x00";
this.JpegMeta.JpegFile.prototype._EXIF_IDENT = "Exif\x00";
this.JpegMeta.JpegFile.prototype._types = {
	1 : [ "BYTE", 1 ],
	2 : [ "ASCII", 1 ],
	3 : [ "SHORT", 2 ],
	4 : [ "LONG", 4 ],
	5 : [ "RATIONAL", 8 ],
	6 : [ "SBYTE", 1 ],
	7 : [ "UNDEFINED", 1 ],
	8 : [ "SSHORT", 2 ],
	9 : [ "SLONG", 4 ],
	10 : [ "SRATIONAL", 8 ],
	11 : [ "FLOAT", 4 ],
	12 : [ "DOUBLE", 8 ]
};
this.JpegMeta.JpegFile.prototype._tifftags = {
	256 : [ "Image width", "ImageWidth" ],
	257 : [ "Image height", "ImageLength" ],
	258 : [ "Number of bits per component", "BitsPerSample" ],
	259 : [ "Compression scheme", "Compression", {
		1 : "uncompressed",
		6 : "JPEG compression"
	} ],
	262 : [ "Pixel composition", "PhotmetricInerpretation", {
		2 : "RGB",
		6 : "YCbCr"
	} ],
	274 : [ "Orientation of image", "Orientation", {
		1 : "Normal",
		2 : "Reverse?",
		3 : "Upside-down",
		4 : "Upside-down Reverse",
		5 : "90 degree CW",
		6 : "90 degree CW reverse",
		7 : "90 degree CCW",
		8 : "90 degree CCW reverse"
	} ],
	277 : [ "Number of components", "SamplesPerPixel" ],
	284 : [ "Image data arrangement", "PlanarConfiguration", {
		1 : "chunky format",
		2 : "planar format"
	} ],
	530 : [ "Subsampling ratio of Y to C", "YCbCrSubSampling" ],
	531 : [ "Y and C positioning", "YCbCrPositioning", {
		1 : "centered",
		2 : "co-sited"
	} ],
	282 : [ "X Resolution", "XResolution" ],
	283 : [ "Y Resolution", "YResolution" ],
	296 : [ "Resolution Unit", "ResolutionUnit", {
		2 : "inches",
		3 : "centimeters"
	} ],
	273 : [ "Image data location", "StripOffsets" ],
	278 : [ "Number of rows per strip", "RowsPerStrip" ],
	279 : [ "Bytes per compressed strip", "StripByteCounts" ],
	513 : [ "Offset to JPEG SOI", "JPEGInterchangeFormat" ],
	514 : [ "Bytes of JPEG Data", "JPEGInterchangeFormatLength" ],
	301 : [ "Transfer function", "TransferFunction" ],
	318 : [ "White point chromaticity", "WhitePoint" ],
	319 : [ "Chromaticities of primaries", "PrimaryChromaticities" ],
	529 : [ "Color space transformation matrix coefficients",
			"YCbCrCoefficients" ],
	532 : [ "Pair of black and white reference values", "ReferenceBlackWhite" ],
	306 : [ "Date and time", "DateTime" ],
	270 : [ "Image title", "ImageDescription" ],
	271 : [ "Make", "Make" ],
	272 : [ "Model", "Model" ],
	305 : [ "Software", "Software" ],
	315 : [ "Person who created the image", "Artist" ],
	316 : [ "Host Computer", "HostComputer" ],
	33432 : [ "Copyright holder", "Copyright" ],
	34665 : [ "Exif tag", "ExifIfdPointer" ],
	34853 : [ "GPS tag", "GPSInfoIfdPointer" ]
};
this.JpegMeta.JpegFile.prototype._exiftags = {
	36864 : [ "Exif Version", "ExifVersion" ],
	40960 : [ "FlashPix Version", "FlashpixVersion" ],
	40961 : [ "Color Space", "ColorSpace" ],
	37121 : [ "Meaning of each component", "ComponentsConfiguration" ],
	37122 : [ "Compressed Bits Per Pixel", "CompressedBitsPerPixel" ],
	40962 : [ "Pixel X Dimension", "PixelXDimension" ],
	40963 : [ "Pixel Y Dimension", "PixelYDimension" ],
	37500 : [ "Manufacturer notes", "MakerNote" ],
	37510 : [ "User comments", "UserComment" ],
	40964 : [ "Related audio file", "RelatedSoundFile" ],
	36867 : [ "Date Time Original", "DateTimeOriginal" ],
	36868 : [ "Date Time Digitized", "DateTimeDigitized" ],
	37520 : [ "DateTime subseconds", "SubSecTime" ],
	37521 : [ "DateTimeOriginal subseconds", "SubSecTimeOriginal" ],
	37522 : [ "DateTimeDigitized subseconds", "SubSecTimeDigitized" ],
	33434 : [ "Exposure time", "ExposureTime" ],
	33437 : [ "FNumber", "FNumber" ],
	34850 : [ "Exposure program", "ExposureProgram" ],
	34852 : [ "Spectral sensitivity", "SpectralSensitivity" ],
	34855 : [ "ISO Speed Ratings", "ISOSpeedRatings" ],
	34856 : [ "Optoelectric coefficient", "OECF" ],
	37377 : [ "Shutter Speed", "ShutterSpeedValue" ],
	37378 : [ "Aperture Value", "ApertureValue" ],
	37379 : [ "Brightness", "BrightnessValue" ],
	37380 : [ "Exposure Bias Value", "ExposureBiasValue" ],
	37381 : [ "Max Aperture Value", "MaxApertureValue" ],
	37382 : [ "Subject Distance", "SubjectDistance" ],
	37383 : [ "Metering Mode", "MeteringMode" ],
	37384 : [ "Light Source", "LightSource" ],
	37385 : [ "Flash", "Flash" ],
	37386 : [ "Focal Length", "FocalLength" ],
	37396 : [ "Subject Area", "SubjectArea" ],
	41483 : [ "Flash Energy", "FlashEnergy" ],
	41484 : [ "Spatial Frequency Response", "SpatialFrequencyResponse" ],
	41486 : [ "Focal Plane X Resolution", "FocalPlaneXResolution" ],
	41487 : [ "Focal Plane Y Resolution", "FocalPlaneYResolution" ],
	41488 : [ "Focal Plane Resolution Unit", "FocalPlaneResolutionUnit" ],
	41492 : [ "Subject Location", "SubjectLocation" ],
	41493 : [ "Exposure Index", "ExposureIndex" ],
	41495 : [ "Sensing Method", "SensingMethod" ],
	41728 : [ "File Source", "FileSource" ],
	41729 : [ "Scene Type", "SceneType" ],
	41730 : [ "CFA Pattern", "CFAPattern" ],
	41985 : [ "Custom Rendered", "CustomRendered" ],
	41986 : [ "Exposure Mode", "Exposure Mode" ],
	41987 : [ "White Balance", "WhiteBalance" ],
	41988 : [ "Digital Zoom Ratio", "DigitalZoomRatio" ],
	41990 : [ "Scene Capture Type", "SceneCaptureType" ],
	41991 : [ "Gain Control", "GainControl" ],
	41992 : [ "Contrast", "Contrast" ],
	41993 : [ "Saturation", "Saturation" ],
	41994 : [ "Sharpness", "Sharpness" ],
	41995 : [ "Device settings description", "DeviceSettingDescription" ],
	41996 : [ "Subject distance range", "SubjectDistanceRange" ],
	42016 : [ "Unique image ID", "ImageUniqueID" ],
	40965 : [ "Interoperability tag", "InteroperabilityIFDPointer" ]
};
this.JpegMeta.JpegFile.prototype._gpstags = {
	0 : [ "GPS tag version", "GPSVersionID" ],
	1 : [ "North or South Latitude", "GPSLatitudeRef" ],
	2 : [ "Latitude", "GPSLatitude" ],
	3 : [ "East or West Longitude", "GPSLongitudeRef" ],
	4 : [ "Longitude", "GPSLongitude" ],
	5 : [ "Altitude reference", "GPSAltitudeRef" ],
	6 : [ "Altitude", "GPSAltitude" ],
	7 : [ "GPS time (atomic clock)", "GPSTimeStamp" ],
	8 : [ "GPS satellites usedd for measurement", "GPSSatellites" ],
	9 : [ "GPS receiver status", "GPSStatus" ],
	10 : [ "GPS mesaurement mode", "GPSMeasureMode" ],
	11 : [ "Measurement precision", "GPSDOP" ],
	12 : [ "Speed unit", "GPSSpeedRef" ],
	13 : [ "Speed of GPS receiver", "GPSSpeed" ],
	14 : [ "Reference for direction of movement", "GPSTrackRef" ],
	15 : [ "Direction of movement", "GPSTrack" ],
	16 : [ "Reference for direction of image", "GPSImgDirectionRef" ],
	17 : [ "Direction of image", "GPSImgDirection" ],
	18 : [ "Geodetic survey data used", "GPSMapDatum" ],
	19 : [ "Reference for latitude of destination", "GPSDestLatitudeRef" ],
	20 : [ "Latitude of destination", "GPSDestLatitude" ],
	21 : [ "Reference for longitude of destination", "GPSDestLongitudeRef" ],
	22 : [ "Longitude of destination", "GPSDestLongitude" ],
	23 : [ "Reference for bearing of destination", "GPSDestBearingRef" ],
	24 : [ "Bearing of destination", "GPSDestBearing" ],
	25 : [ "Reference for distance to destination", "GPSDestDistanceRef" ],
	26 : [ "Distance to destination", "GPSDestDistance" ],
	27 : [ "Name of GPS processing method", "GPSProcessingMethod" ],
	28 : [ "Name of GPS area", "GPSAreaInformation" ],
	29 : [ "GPS Date", "GPSDateStamp" ],
	30 : [ "GPS differential correction", "GPSDifferential" ]
};
this.JpegMeta.JpegFile.prototype._markers = {
	0xc0 : [ "SOF0", "_sofHandler", "Baseline DCT" ],
	0xc1 : [ "SOF1", "_sofHandler", "Extended sequential DCT" ],
	0xc2 : [ "SOF2", "_sofHandler", "Progressive DCT" ],
	0xc3 : [ "SOF3", "_sofHandler", "Lossless (sequential)" ],
	0xc5 : [ "SOF5", "_sofHandler", "Differential sequential DCT" ],
	0xc6 : [ "SOF6", "_sofHandler", "Differential progressive DCT" ],
	0xc7 : [ "SOF7", "_sofHandler", "Differential lossless (sequential)" ],
	0xc8 : [ "JPG", null, "Reserved for JPEG extensions" ],
	0xc9 : [ "SOF9", "_sofHandler", "Extended sequential DCT" ],
	0xca : [ "SOF10", "_sofHandler", "Progressive DCT" ],
	0xcb : [ "SOF11", "_sofHandler", "Lossless (sequential)" ],
	0xcd : [ "SOF13", "_sofHandler", "Differential sequential DCT" ],
	0xce : [ "SOF14", "_sofHandler", "Differential progressive DCT" ],
	0xcf : [ "SOF15", "_sofHandler", "Differential lossless (sequential)" ],
	0xc4 : [ "DHT", null, "Define Huffman table(s)" ],
	0xcc : [ "DAC", null, "Define arithmetic coding conditioning(s)" ],
	0xd0 : [ "RST0", null, "Restart with modulo 8 count “0”" ],
	0xd1 : [ "RST1", null, "Restart with modulo 8 count “1”" ],
	0xd2 : [ "RST2", null, "Restart with modulo 8 count “2”" ],
	0xd3 : [ "RST3", null, "Restart with modulo 8 count “3”" ],
	0xd4 : [ "RST4", null, "Restart with modulo 8 count “4”" ],
	0xd5 : [ "RST5", null, "Restart with modulo 8 count “5”" ],
	0xd6 : [ "RST6", null, "Restart with modulo 8 count “6”" ],
	0xd7 : [ "RST7", null, "Restart with modulo 8 count “7”" ],
	0xd8 : [ "SOI", null, "Start of image" ],
	0xd9 : [ "EOI", null, "End of image" ],
	0xda : [ "SOS", null, "Start of scan" ],
	0xdb : [ "DQT", null, "Define quantization table(s)" ],
	0xdc : [ "DNL", null, "Define number of lines" ],
	0xdd : [ "DRI", null, "Define restart interval" ],
	0xde : [ "DHP", null, "Define hierarchical progression" ],
	0xdf : [ "EXP", null, "Expand reference component(s)" ],
	0xe0 : [ "APP0", "_app0Handler", "Reserved for application segments" ],
	0xe1 : [ "APP1", "_app1Handler" ],
	0xe2 : [ "APP2", null ],
	0xe3 : [ "APP3", null ],
	0xe4 : [ "APP4", null ],
	0xe5 : [ "APP5", null ],
	0xe6 : [ "APP6", null ],
	0xe7 : [ "APP7", null ],
	0xe8 : [ "APP8", null ],
	0xe9 : [ "APP9", null ],
	0xea : [ "APP10", null ],
	0xeb : [ "APP11", null ],
	0xec : [ "APP12", null ],
	0xed : [ "APP13", null ],
	0xee : [ "APP14", null ],
	0xef : [ "APP15", null ],
	0xf0 : [ "JPG0", null ],
	0xf1 : [ "JPG1", null ],
	0xf2 : [ "JPG2", null ],
	0xf3 : [ "JPG3", null ],
	0xf4 : [ "JPG4", null ],
	0xf5 : [ "JPG5", null ],
	0xf6 : [ "JPG6", null ],
	0xf7 : [ "JPG7", null ],
	0xf8 : [ "JPG8", null ],
	0xf9 : [ "JPG9", null ],
	0xfa : [ "JPG10", null ],
	0xfb : [ "JPG11", null ],
	0xfc : [ "JPG12", null ],
	0xfd : [ "JPG13", null ],
	0xfe : [ "COM", null ],
	0x01 : [ "JPG13", null ]
};
this.JpegMeta.JpegFile.prototype._addMetaGroup = function _addMetaGroup(name,
		description) {
	var group = new JpegMeta.MetaGroup(name, description);
	this[group.fieldName] = group;
	this.metaGroups[group.fieldName] = group;
	return group;
};
this.JpegMeta.JpegFile.prototype._parseIfd = function _parseIfd(endian,
		_binary_data, base, ifd_offset, tags, name, description) {
	var num_fields = JpegMeta.parseNum(endian, _binary_data, base + ifd_offset,
			2);
	var i, j;
	var tag_base;
	var tag_field;
	var type, type_field, type_size;
	var num_values;
	var value_offset;
	var value;
	var _val;
	var num;
	var den;
	var group;
	group = this._addMetaGroup(name, description);
	for ( var i = 0; i < num_fields; i++) {
		tag_base = base + ifd_offset + 2 + (i * 12);
		tag_field = JpegMeta.parseNum(endian, _binary_data, tag_base, 2);
		// console.log('tag-field=' + tag_field)
		type_field = JpegMeta.parseNum(endian, _binary_data, tag_base + 2, 2);
		num_values = JpegMeta.parseNum(endian, _binary_data, tag_base + 4, 4);
		value_offset = JpegMeta.parseNum(endian, _binary_data, tag_base + 8, 4);
		if (this._types[type_field] === undefined) {
			continue;
		}
		type = this._types[type_field][0];
		type_size = this._types[type_field][1];
		if (type_size * num_values <= 4) {
			value_offset = tag_base + 8;
		} else {
			value_offset = base + value_offset;
		}
		if (type == "UNDEFINED") {
			f = _binary_data.slice(value_offset, value_offset + num_values);
		} else if (type == "ASCII") {
			value = _binary_data.slice(value_offset, value_offset + num_values);
			value = value.split('\x00')[0];
		} else {
			value = new Array();
			for (j = 0; j < num_values; j++, value_offset += type_size) {
				if (type == "BYTE" || type == "SHORT" || type == "LONG") {
					value.push(JpegMeta.parseNum(endian, _binary_data,
							value_offset, type_size));
				}
				if (type == "SBYTE" || type == "SSHORT" || type == "SLONG") {
					value.push(JpegMeta.parseSnum(endian, _binary_data,
							value_offset, type_size));
				}
				if (type == "RATIONAL") {
					num = JpegMeta.parseNum(endian, _binary_data, value_offset,
							4);
					den = JpegMeta.parseNum(endian, _binary_data,
							value_offset + 4, 4);
					value.push(new JpegMeta.Rational(num, den));
				}
				if (type == "SRATIONAL") {
					num = JpegMeta.parseSnum(endian, _binary_data,
							value_offset, 4);
					den = JpegMeta.parseSnum(endian, _binary_data,
							value_offset + 4, 4);
					value.push(new JpegMeta.Rational(num, den));
				}
				value.push();
			}
			if (num_values === 1) {
				value = value[0];
			}
		}
		if (tags[tag_field] !== undefined) {
			group._addProperty(tags[tag_field][1], tags[tag_field][0], value);
		}
	}
};
this.JpegMeta.JpegFile.prototype._jfifHandler = function _jfifHandler(mark, pos) {
	if (this.jfif !== undefined) {
		throw Error("Multiple JFIF segments found");
	}
	this._addMetaGroup("jfif", "JFIF");
	this.jfif._addProperty("version_major", "Version Major", this._binary_data
			.charCodeAt(pos + 5));
	this.jfif._addProperty("version_minor", "Version Minor", this._binary_data
			.charCodeAt(pos + 6));
	this.jfif
			._addProperty("version", "JFIF Version",
					this.jfif.version_major.value + "."
							+ this.jfif.version_minor.value);
	this.jfif._addProperty("units", "Density Unit", this._binary_data
			.charCodeAt(pos + 7));
	this.jfif._addProperty("Xdensity", "X density", JpegMeta.parseNum(">",
			this._binary_data, pos + 8, 2));
	this.jfif._addProperty("Ydensity", "Y Density", JpegMeta.parseNum(">",
			this._binary_data, pos + 10, 2));
	this.jfif._addProperty("Xthumbnail", "X Thumbnail", JpegMeta.parseNum(">",
			this._binary_data, pos + 12, 1));
	this.jfif._addProperty("Ythumbnail", "Y Thumbnail", JpegMeta.parseNum(">",
			this._binary_data, pos + 13, 1));
};
this.JpegMeta.JpegFile.prototype._app0Handler = function app0Handler(mark, pos) {
	var ident = this._binary_data.slice(pos, pos + 5);
	if (ident == this._JFIF_IDENT) {
		this._jfifHandler(mark, pos);
	} else if (ident == this._JFXX_IDENT) {
	} else {
	}
};
this.JpegMeta.JpegFile.prototype._app1Handler = function _app1Handler(mark, pos) {
	var ident = this._binary_data.slice(pos, pos + 5);
	if (ident == this._EXIF_IDENT) {
		this._exifHandler(mark, pos + 6);
	} else {
	}
};
JpegMeta.JpegFile.prototype._exifHandler = function _exifHandler(mark, pos) {
	if (this.exif !== undefined) {
		throw new Error("Multiple JFIF segments found");
	}
	var endian;
	var magic_field;
	var ifd_offset;
	var primary_ifd, exif_ifd, gps_ifd;
	var endian_field = this._binary_data.slice(pos, pos + 2);
	if (endian_field === "II") {
		endian = "<";
	} else if (endian_field === "MM") {
		endian = ">";
	} else {
		throw new Error("Malformed TIFF meta-data. Unknown endianess: "
				+ endian_field);
	}
	magic_field = JpegMeta.parseNum(endian, this._binary_data, pos + 2, 2);
	if (magic_field !== 42) {
		throw new Error("Malformed TIFF meta-data. Bad magic: " + magic_field);
	}
	ifd_offset = JpegMeta.parseNum(endian, this._binary_data, pos + 4, 4);
	this._parseIfd(endian, this._binary_data, pos, ifd_offset, this._tifftags,
			"tiff", "TIFF");
	// console.log('.,.,.,.,.' + this.tiff.ExifIfdPointer.value)
	if (this.tiff.ExifIfdPointer) {
		// console.log('has pointer1')
		this._parseIfd(endian, this._binary_data, pos,
				this.tiff.ExifIfdPointer.value, this._exiftags, "exif", "Exif");
	}
	if (this.tiff.GPSInfoIfdPointer) {
		this._parseIfd(endian, this._binary_data, pos,
				this.tiff.GPSInfoIfdPointer.value, this._gpstags, "gps", "GPS");
		if (this.gps.GPSLatitude) {
			var latitude;
			latitude = this.gps.GPSLatitude.value[0].asFloat() + (1 / 60)
					* this.gps.GPSLatitude.value[1].asFloat() + (1 / 3600)
					* this.gps.GPSLatitude.value[2].asFloat();
			if (this.gps.GPSLatitudeRef.value === "S") {
				latitude = -latitude;
			}
			this.gps._addProperty("latitude", "Dec. Latitude", latitude);
		}
		if (this.gps.GPSLongitude) {
			var longitude;
			longitude = this.gps.GPSLongitude.value[0].asFloat() + (1 / 60)
					* this.gps.GPSLongitude.value[1].asFloat() + (1 / 3600)
					* this.gps.GPSLongitude.value[2].asFloat();
			if (this.gps.GPSLongitudeRef.value === "W") {
				longitude = -longitude;
			}
			this.gps._addProperty("longitude", "Dec. Longitude", longitude);
		}
	}
}